﻿using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace XNAssist
{
    /// <summary>
    /// A rectangle that can be expanded to any size without losing the resolution of the borders.
    /// </summary>
    public class NineTile
    {
        /// <summary>
        /// The texture to draw with
        /// </summary>
        public Texture2D NineTileTexture { get; private set; }

        /// <summary>
        /// The size of the horizontal borders in pixels (inside the texture)
        /// </summary>
        public int HBorderTextureSize { get; private set; }

        /// <summary>
        /// The size of the vertical borders in pixels (inside the texture)
        /// </summary>
        public int VBorderTextureSize { get; private set; }

        /// <summary>
        /// The scale of the horizontal borders
        /// </summary>
        public float HBorderScale { get; private set; }

        /// <summary>
        /// The scale of the vertical borders
        /// </summary>
        public float VBorderScale { get; private set; }

        /// <summary>
        /// A basic NineTile constructor
        /// </summary>
        /// <param name="texture"> The texture (with all parts) to draw with </param>
        /// <param name="hBorderTextureSize"> The size of the horizontal border parts (inside the texture) </param>
        /// <param name="vBorderTextureSize"> The size of the vertical border parts (inside the texture) </param>
        public NineTile(Texture2D texture, int hBorderTextureSize, int vBorderTextureSize)
        {
            NineTileTexture = texture;
            HBorderTextureSize = hBorderTextureSize;
            VBorderTextureSize = vBorderTextureSize;
            HBorderScale = 1f;
            VBorderScale = 1f;
        }

        /// <summary>
        /// A basic NineTile constructor
        /// </summary>
        /// <param name="texture"> The texture (with all parts) to draw with </param>
        /// <param name="hBorderTextureSize"> The size of the horizontal border parts (inside the texture) </param>
        /// <param name="vBorderTextureSize"> The size of the vertical border parts (inside the texture) </param>
        /// <param name="borderScale"> The scale of the border parts (for drawing) </param>
        public NineTile(Texture2D texture, int hBorderTextureSize, int vBorderTextureSize, float borderScale)
        {
            NineTileTexture = texture;
            HBorderTextureSize = hBorderTextureSize;
            VBorderTextureSize = vBorderTextureSize;
            HBorderScale = borderScale;
            VBorderScale = borderScale;
        }

        /// <summary>
        /// A basic NineTile constructor
        /// </summary>
        /// <param name="texture"> The texture (with all parts) to draw with </param>
        /// <param name="hBorderTextureSize"> The size of the horizontal border parts (inside the texture) </param>
        /// <param name="vBorderTextureSize"> The size of the vertical border parts (inside the texture) </param>
        /// <param name="hBorderScale"> The scale of the horizontal border parts (for drawing) </param>
        /// <param name="vBorderScale"> The scale of the vertical border parts (for drawing) </param>
        public NineTile(Texture2D texture, int hBorderTextureSize, int vBorderTextureSize, float hBorderScale, float vBorderScale)
        {
            NineTileTexture = texture;
            HBorderTextureSize = hBorderTextureSize;
            VBorderTextureSize = vBorderTextureSize;
            HBorderScale = hBorderScale;
            VBorderScale = vBorderScale;
        }

        /// <summary>
        /// Draws the NineTile
        /// </summary>
        /// <param name="spriteBatch"> The SpriteBatch to draw to </param>
        /// <param name="position"> The position to draw at (based on the upper left) </param>
        /// <param name="width"> The width to draw the rectangle at </param>
        /// <param name="height"> The height to draw the rectangle at </param>
        /// <param name="color"> The color to draw with </param>
        public void Draw(SpriteBatch spriteBatch, Vector2 position, int width, int height, Color color)
        {
            #region Clamp Dimensions

            if (width < 2*VBorderTextureSize*VBorderScale)
                width = (int)(2*VBorderTextureSize*VBorderScale);
            if (height < 2 * HBorderTextureSize * HBorderScale)
                height = (int)(2 * HBorderTextureSize * HBorderScale);

            #endregion

            #region Draw Corners

            var ulCornerRect = new Rectangle((int) position.X, (int) position.Y,
                (int) (VBorderTextureSize*VBorderScale), (int) (HBorderTextureSize*HBorderScale));

            var urCornerRect = new Rectangle((int) position.X + (width - (int) (VBorderTextureSize*VBorderScale)),
                (int) position.Y,
                (int) (VBorderTextureSize*VBorderScale), (int) (HBorderTextureSize*HBorderScale));

            var llCornerRect = new Rectangle((int) position.X,
                (int) position.Y + (height - (int) (HBorderTextureSize*HBorderScale)),
                (int) (VBorderTextureSize*VBorderScale), (int) (HBorderTextureSize*HBorderScale));

            var lrCornerRect = new Rectangle((int) position.X + (width - (int) (VBorderTextureSize*VBorderScale)),
                (int) position.Y + (height - (int) (HBorderTextureSize*HBorderScale)),
                (int) (VBorderTextureSize*VBorderScale), (int) (HBorderTextureSize*HBorderScale));

            spriteBatch.Draw(NineTileTexture, ulCornerRect, new Rectangle(0, 0, VBorderTextureSize, HBorderTextureSize), color);
            spriteBatch.Draw(NineTileTexture, urCornerRect, new Rectangle(NineTileTexture.Width - VBorderTextureSize, 0, VBorderTextureSize, HBorderTextureSize), color);
            spriteBatch.Draw(NineTileTexture, llCornerRect, new Rectangle(0, NineTileTexture.Height - HBorderTextureSize, VBorderTextureSize, HBorderTextureSize), color);
            spriteBatch.Draw(NineTileTexture, lrCornerRect, new Rectangle(NineTileTexture.Width - VBorderTextureSize, NineTileTexture.Height - HBorderTextureSize, VBorderTextureSize, HBorderTextureSize), color);

            #endregion

            #region Draw Edges

            var uBorderRect = new Rectangle((int) position.X + (int) (VBorderTextureSize*VBorderScale), (int) position.Y,
                width - (int)(2 * VBorderTextureSize * VBorderScale), (int)(HBorderTextureSize * HBorderScale));

            var dBorderRect = new Rectangle((int)position.X + (int)(VBorderTextureSize * VBorderScale), (int)position.Y + (int)(height - (HBorderTextureSize * HBorderScale)),
                width - (int)(2 * VBorderTextureSize * VBorderScale), (int)(HBorderTextureSize * HBorderScale));

            var lBorderRect = new Rectangle((int)position.X, (int)position.Y + (int)(HBorderTextureSize * HBorderScale),
                (int)(VBorderTextureSize * VBorderScale), height - (int)(2 * HBorderTextureSize * HBorderScale));

            var rBorderRect = new Rectangle((int)position.X + (int)(width - (VBorderTextureSize * VBorderScale)), (int)position.Y + (int)(HBorderTextureSize * HBorderScale),
                (int)(VBorderTextureSize * VBorderScale), height - (int)(2 * HBorderTextureSize * HBorderScale));

            spriteBatch.Draw(NineTileTexture, uBorderRect, new Rectangle(VBorderTextureSize, 0, NineTileTexture.Width - (2 * HBorderTextureSize), HBorderTextureSize), color);
            spriteBatch.Draw(NineTileTexture, dBorderRect, new Rectangle(VBorderTextureSize, NineTileTexture.Height - HBorderTextureSize, NineTileTexture.Width - (2 * VBorderTextureSize), HBorderTextureSize), color);
            spriteBatch.Draw(NineTileTexture, lBorderRect, new Rectangle(0, VBorderTextureSize, VBorderTextureSize, NineTileTexture.Height - (2 * HBorderTextureSize)), color);
            spriteBatch.Draw(NineTileTexture, rBorderRect, new Rectangle(NineTileTexture.Width - VBorderTextureSize, HBorderTextureSize, VBorderTextureSize, NineTileTexture.Height - (2 * HBorderTextureSize)), color);

            #endregion

            #region Draw Center

            var centerRect = new Rectangle((int) position.X + (int) (VBorderTextureSize*VBorderScale),
                (int) position.Y + (int) (HBorderTextureSize*HBorderScale),
                width - (int) (2*VBorderTextureSize*VBorderScale), height - (int) (2*HBorderTextureSize*HBorderScale));

            spriteBatch.Draw(NineTileTexture, centerRect,
                new Rectangle(VBorderTextureSize, HBorderTextureSize, NineTileTexture.Width - (2*VBorderTextureSize),
                    NineTileTexture.Height - (2*HBorderTextureSize)), color);

            #endregion
        }
    }
}
